﻿using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace TianShiProject.JWTHelper
{
    public class TokenManager
    {
        /// <summary>
        /// 生成token
        /// </summary>
        /// <param name="tokenStr">需要签名的数据 默认为用户的对象</param>
        /// <param name="expireHour">默认3天过期</param>
        /// <returns>返回token字符串</returns>
        public static string GenerateToken(string tokenStr, int expireHour = 3 * 24) //3天过期
        {
            // 1. Create Security Token Handler
            var tokenHandler = new JwtSecurityTokenHandler();


            var configuration = GetManager.BuildConfiguration();


            // 2. Create Private Key to Encrypted
            var tokenKey = Encoding.ASCII.GetBytes(configuration["Authentication:SecretKey"]);

            //3. Create JETdescriptor
            var tokenDescriptor = new SecurityTokenDescriptor()
            {
                Subject = new ClaimsIdentity(
                    new Claim[]
                    {
                        new Claim(ClaimTypes.Name, tokenStr),
                        //new Claim(ClaimTypes.Role,"")
                    }),
                Expires = DateTime.UtcNow.AddHours(expireHour),
                SigningCredentials = new SigningCredentials(
                    new SymmetricSecurityKey(tokenKey), SecurityAlgorithms.HmacSha256Signature)
            };
            //4. Create Token
            var token = tokenHandler.CreateToken(tokenDescriptor);

            // 5. Return Token from method
            return tokenHandler.WriteToken(token);
        }

        /// <summary>
        /// 得到Token中的验证消息
        /// </summary>
        /// <param name="token"></param>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static string ValidateToken(string token, out DateTime dateTime)
        {
            dateTime = DateTime.Now;
            var principal = GetPrincipal(token, out dateTime);

            if (principal == null)
                return default(string);

            ClaimsIdentity identity = null;
            try
            {
                identity = (ClaimsIdentity)principal.Identity;
            }
            catch (NullReferenceException)
            {
                return null;
            }
            //identity.FindFirst(ClaimTypes.Name).Value;
            return identity.FindFirst("sid").Value;
        }

        /// <summary>
        /// 从Token中得到ClaimsPrincipal对象
        /// </summary>
        /// <param name="token"></param>
        /// <param name="dateTime">返回过期时间</param>
        /// <returns></returns>
        private static ClaimsPrincipal GetPrincipal(string token, out DateTime dateTime)
        {
            try
            {
                dateTime = DateTime.Now;
                var tokenHandler = new JwtSecurityTokenHandler();
                var jwtToken = (JwtSecurityToken)tokenHandler.ReadToken(token);

                if (jwtToken == null)
                    return null;

                var configuration = GetManager.BuildConfiguration();

                var key = Convert.FromBase64String(configuration["Authentication:SecretKey"]);

                var parameters = new TokenValidationParameters()
                {
                    RequireExpirationTime = true,
                    ValidateIssuer = true,//验证创建该令牌的发布者
                    ValidateLifetime = true,//检查令牌是否未过期，以及发行者的签名密钥是否有效
                    ValidateAudience = false,//确保令牌的接收者有权接收它
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidIssuer = configuration["Authentication:Issuer"]//验证创建该令牌的发布者
                };
                //验证token 
                var principal = tokenHandler.ValidateToken(token, parameters, out var securityToken);
                //若开始时间大于当前时间 或结束时间小于当前时间 则返回空
                if (securityToken.ValidFrom.ToLocalTime() > DateTime.Now || securityToken.ValidTo.ToLocalTime() < DateTime.Now)
                {
                    dateTime = DateTime.Now;
                    return null;
                }
                dateTime = securityToken.ValidTo.ToLocalTime();//返回Token结束时间
                return principal;
            }
            catch (Exception e)
            {
                dateTime = DateTime.Now;
                //LogHelper.Logger.Fatal(e, "Token验证失败");
                return null;
            }
        }
    }

    public class GetManager
    {
        public static IConfigurationRoot BuildConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../TianShiProject.Web/"))
                .AddJsonFile("appsettings.json", optional: false);

            return builder.Build();
        }
    }
}
